/*
# PostgreSQL Database Modeler (pgModeler)
#
# Copyright 2006-2025 - Raphael Araújo e Silva <raphael@pgmodeler.io>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# The complete text of GPLv3 is at LICENSE file on source code root directory.
# Also, you can get the complete GNU General Public License at <http://www.gnu.org/licenses/>
*/

/**
\ingroup libcore
\class BaseRelationship
\brief Implements the basic operations to manipulate relationships between tables
\note <strong>Creation date:</strong> 09/04/2008
*/

#ifndef BASE_RELATIONSHIP_H
#define BASE_RELATIONSHIP_H

#include "textbox.h"
#include "constraint.h"
#include <cmath>
#include <QColor>

class __libcore BaseRelationship: public BaseGraphicObject  {
	public:
		//! \brief Constants used to assign the type to relationship
		enum RelType: unsigned {
			Relationship11=10, //! \brief One to one
			Relationship1n=11, //! \brief One to many
			RelationshipNn=12, //! \brief Many to many
			RelationshipGen=13, //! \brief Generalization (Inheritance)
			RelationshipDep=14, //! \brief Dependency (table-view) / Copy (table-table)
			RelationshipPart=15,//! \brief Partitioning relationship
			RelationshipFk=16//! \brief Relationship generated by creating a foreign key manually on a table
		};

	protected:
		//! \brief This attribute stores the foreign key used to generate the relationship (only for FK relationships)
		Constraint *reference_fk;

		//! \brief This attribute overrides the default color configuration for relationship line and descriptor
		QColor custom_color;

		//! \brief Represents the points added by the user on the relationship line
		std::vector<QPointF> points;

		//! \brief Indicates whether the relationship is linked to the tables
		bool connected;

		//! \brief Indicates the mandatory participation of source and destination tables
		bool dst_mandatory, src_mandatory;

		/*! \brief Relationship lables:
		 0 - Source cardinality
		 1 - Destination cardinality
		 2 - Relationship name */
		Textbox *lables[3];

		/*! \brief Stores the distances of the labels from its respectively origins.
		 This is used to controle de position of the labels when they are
		 moved by the user */
		QPointF lables_dist[3];

		//! \brief Entities envolved on the relationship
		BaseTable *src_table,
		*dst_table;

		/*! \brief Relationship type. See enum RelationshipType */
		RelType rel_type;

		//! \brief Sets the attributes used on the generation of XML definition for relationship
		void setRelationshipAttributes();

		//! \brief Makes the initial configuration creating the labels
		void configureRelationship();

		//! \brief Marks the flag indicating that relationship is connected
		void connectRelationship();

		//! \brief Uncheck the flag indicating that relationship is disconnected
		void disconnectRelationship();

		//! \brief Toggles the connected flag and forces the tables/schemas/relationship update
		void setConnected(bool value);

		QString getCachedCode(unsigned def_type);

		QString getDropCode(bool) final
		{
			return "";
		}

		void setReferenceForeignKey(Constraint *ref_fk);

		void configureSearchAttributes() override;

	public:
		//! \brief Constants used to reference the relationship labels
		enum LabelId: unsigned {
			SrcCardLabel,
			DstCardLabel,
			RelNameLabel
		};

		//! \brief Constants used to reference the source and destination tables
		enum TableId: unsigned {
			SrcTable,
			DstTable
		};

		BaseRelationship(BaseRelationship *rel);

		BaseRelationship(RelType rel_type, BaseTable *src_tab, BaseTable *dst_tab, bool src_mandatory, bool dst_mandatory);

		~BaseRelationship() override;

		//! \brief Sets the name of the relationship
		void setName(const QString &name) override;

		//! \brief Sets the mandatory participation for the specified table (Via constants SRC_TABLE | DST_TABLE)
		void setMandatoryTable(TableId table_id, bool value);

		//! \brief Return one relationship label using its id (Via constants LABEL_???)
		Textbox *getLabel(LabelId label_id);

		//! \brief Returns one of the participant tables (Via constants SRC_TABLE | DST_TABLE)
		BaseTable *getTable(TableId table_id);

		//! \brief Returns the relationship type
		RelType getRelationshipType();

		//! \brief Returns the mandatory participation for the specified table (Via constants SRC_TABLE | DST_TABLE)
		bool isTableMandatory(TableId table_id);

		//! \brief Returns the relationship connection state
		bool isRelationshipConnected();

		/*! \brief Since base relationships doesn't has SQL code definition this method will return a empty
		definition whenever the user try to generate a SQL for this object. */
		QString getSourceCode(SchemaParser::CodeType def_type) override;

		//! \brief Returns whether the table is linked to itself via relationship (self-relationship)
		bool isSelfRelationship();

		//! \brief Stores the points that defines the custom relationship line
		void setPoints(const std::vector<QPointF> &points);

		//! \brief Returns the relationship point list
		std::vector<QPointF> getPoints();

		//! \brief Sets the distance of the specified label in relation to its origin
		void setLabelDistance(LabelId label_id, QPointF label_dist);

		//! \brief Gets the distance of the specified label in relation to its origin
		QPointF getLabelDistance(LabelId label_id);

		void setCustomColor(const QColor &color);

		QColor getCustomColor();

		void resetLabelsDistance();

		Constraint *getReferenceForeignKey();

		/*! \brief Returns true when the FK relationship can simulate a one-to-one relationship
		 * In that case, there's a unique key in which the foreign key(s) columns is part of. */
		bool canSimulateRelationship11();

		//! \brief Assigns one relationship to other making the appropriate attribute copy
		void operator = (BaseRelationship &rel);

		QString getRelTypeAttribute();

		void setCodeInvalidated(bool value) override;

		QString getAlterCode(BaseObject *) override
		{
			return "";
		}

		static QString getRelationshipTypeName(RelType rel_type, bool is_view = false);

		QString getRelationshipTypeName();

		void updateDependencies() override;

		friend class DatabaseModel;
		friend class RelationshipWidget;
		friend class ModelWidget;
};

#endif
